package com.example.redis;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.connection.RedisStringCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.data.redis.core.types.Expiration;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.Response;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author syg
 * @description 基于redis的 滑动窗口限流
 * @date 2021/12/27 15:26
 */
@Component
@Slf4j
public class SlidingLimit {

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Autowired
    RedisScript<Boolean> SlidingLimitScript;


    /**
     * @param key      键值Key
     * @param obj      此对象在set中不能重复，如有重复会更新score
     * @param timeWin  时间窗口
     * @param maxCount 每次时间窗口容忍的最大请求数量
     * @return
     */
    public Boolean isActionAllow(String key, Object obj, int timeWin, int maxCount) {
        if (StringUtils.isEmpty(key) || null == obj || timeWin == 0 || maxCount == 0) {
            return false;
        }
        long curTime = System.currentTimeMillis();
        Boolean allow = redisTemplate.execute(SlidingLimitScript, Collections.singletonList(key), String.valueOf(maxCount), String.valueOf(curTime), String.valueOf(curTime), String.valueOf(timeWin));

//        ZSetOperations opsForZSet = redisTemplate.opsForZSet();
//        opsForZSet.add(key, String.valueOf(curTime), curTime);
//        opsForZSet.removeRangeByScore(key, 0, curTime - (timeWin * 1000));
//        Long count = opsForZSet.zCard(key);
//        redisTemplate.expire(key, timeWin, TimeUnit.SECONDS);
//        return count <= maxCount;
        return allow;
    }

}
